package com.code.soulnetty.modbus.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.net.InetSocketAddress;
import java.util.function.Supplier;

/**
 * @author lyf
 * @date 2022-12-16 18:44
 */
@Slf4j
public class ModbusServer {

    /**
     *  netty启动类
     */
    private ServerBootstrap bootstrap;
    /**
     * bossGroup，处理 Accept 事件
     */
    private EventLoopGroup bossGroup;
    /**
     * workerGroup，处理 业务事件
     */
    private EventLoopGroup workerGroup;
    /**
     * channelHandler的组合类
     */
    private ChannelInitializer<EpollSocketChannel> channelInitializer;

    // IO模型
    private String transportType;

    private Supplier<ChannelHandler[]> channelHandlers;

    public ModbusServer(String transportType, Supplier<ChannelHandler[]> channelHandlers) {
        this.transportType = transportType;
        this.channelHandlers = channelHandlers;
    }

    public void init() {
        initBootStrap();
        bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                .childHandler(channelInitializer);

    }

    private void initBootStrap() {
        if (StringUtils.equals("EPOLL", transportType)) {
            bootstrap = new ServerBootstrap();
            bossGroup = new EpollEventLoopGroup();
            workerGroup = new EpollEventLoopGroup();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(EpollServerSocketChannel.class);
            channelInitializer = new ChannelInitializer<EpollSocketChannel>() {
                @Override
                protected void initChannel(EpollSocketChannel ch) throws Exception {
                    ch.pipeline().addLast(channelHandlers.get());
                }
            };
            return;
        }
        bootstrap = new ServerBootstrap();
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class);
        channelInitializer = new ChannelInitializer<EpollSocketChannel>() {
            @Override
            protected void initChannel(EpollSocketChannel ch) throws Exception {
                ch.pipeline().addLast(channelHandlers.get());
            }
        };
    }

    public ChannelFuture connect(InetSocketAddress address) {
        return bootstrap.bind(address)
                .addListener(future -> log.info("address:{}, result:{}", address, future.isSuccess()))
                .syncUninterruptibly();
    }

}
